#pragma once
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <iostream>
#include <google/protobuf/map.h>
#include <memory>
#include <unordered_map>
#include <mutex>
#include <cstring>
namespace mymq
{
    // 交换机数据管理
    struct Exchange
    {
        using Ptr = std::shared_ptr<Exchange>;
        std::string name;                                     // 交换机名称
        ExchangeType type;                                    // 交换机类型
        bool durable;                                         // 是否持久化
        bool auto_del;                                        // 是否自动删除
        google::protobuf::Map<std::string, std::string> args; // 其他参数
        Exchange() {}
        Exchange(const std::string ename,
                 const ExchangeType etype,
                 const bool edurable,
                 const bool eauto_del,
                 const google::protobuf::Map<std::string, std::string> eargs) : name(ename),
                                                                                type(etype),
                                                                                durable(edurable),
                                                                                auto_del(eauto_del),
                                                                                args(eargs)
        {
        }
        // 将其他参数里面的kv值转化为特定形式的字符串 ---> key=value&key=value....
        std::string GetArgs()
        {
            std::string result;
            for (auto start = args.begin(); start != args.end(); ++start)
            {
                result += start->first + "=" + start->second + "&";
            }
            return result;
        }
        // 将特定字符串转化为map内的kv值
        void SetArgs(std::string str_args)
        {
            std::string key;
            std::string value;
            std::vector<std::string> result;
            StrHelper::split(str_args, "&", result);
            for (auto &str : result)
            {
                size_t pos = str.find("=");
                key = str.substr(0, pos);
                value = str.substr(pos + 1);
                args[key]=value;
            }
        }
    };

    // 交换机持久化数据管理类---sqlite3
    class ExchangeMapper
    {
    public:
        using ExchangeMap = std::unordered_map<std::string, Exchange::Ptr>;
        ExchangeMapper(const std::string &dbfile) : _sql_helper(dbfile)
        {
            // // 在使用数据库前需要知道该数据库文件的父级目录是否存在
            // std::string path = FileHelper::parentderectory(dbfile); // 截取父级目录
            // if (!FileHelper(path).exists())
            // {
            //     // 不存在就创建
            //     FileHelper::createderectory(path);
            // }
            // // 打开数据库
            // assert(_sql_helper.Open());
            // CreateTable();
            std::string path = FileHelper::parentderectory(dbfile);
            FileHelper::createderectory(path);
            assert(_sql_helper.Open());
            CreateTable();
        }
        // 创建/删除交换机数据表
        void CreateTable()
        {
#define CREATE_TABLE "create table if not exists exchange_table(\
                                name varchar(32) primary key,\
                                type int,\
                                durable int,\
                                auto_delete int,\
                                args varchar(128));"
            bool ret = _sql_helper.Exec(CREATE_TABLE, nullptr, nullptr);
            if (ret == false)
            {
                // 直接终止程序
                ELOG("创建交换机数据库表失败\n");
                abort(); // 直接异常退出
            }
        }
        void RemoveTable()
        {
#define DROP_TABLE_INEXC "drop table if exists exchange_table;"
            _sql_helper.Exec(DROP_TABLE_INEXC, nullptr, nullptr);
        }

        // 新增交换机数据
        bool Insert(Exchange::Ptr &ex)
        {
            std::stringstream ss;
            ss << "insert into exchange_table values(";
            ss << "'" << ex->name << "',";
            ss << "'" << ex->type << "',";
            ss << "'" << ex->durable << "',";
            ss << "'" << ex->auto_del << "',";
            ss << "'" << ex->GetArgs() << "');";
            bool ret = _sql_helper.Exec(ss.str(), nullptr, nullptr);
            if (ret == false)
            {
                ELOG("添加数据失败\n");
                return false;
            }
            return true;
        }
        // 移除交换机数据
        void Remove(const std::string &name)
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "';";
            bool ret = _sql_helper.Exec(ss.str(), nullptr, nullptr);
            if (ret == false)
            {
                ELOG("删除交换机%s失败", name.c_str());
                return;
            }
        }
        // 查询所有交换机数据----将查询到的交换机数据按照name为key值存入map中
        ExchangeMap Recovery()
        {
            ExchangeMap result;
            std::string sql = "select * from exchange_table;";
            _sql_helper.Exec(sql, SelectCallBack, &result);
            return result;
        }

    private:
        static int SelectCallBack(void *arg, int numcol, char **row, char **fields)
        {
            ExchangeMap *map = static_cast<ExchangeMap *>(arg);
            auto exc = std::make_shared<Exchange>();
            exc->name = row[0]; // 第一列
            exc->type = (mymq::ExchangeType)std::stoi(row[1]);
            exc->durable = (bool)std::stoi(row[2]);
            exc->auto_del = (bool)std::stoi(row[3]);
            if (row[4])
                exc->SetArgs(row[4]);
            map->insert(std::make_pair(exc->name, exc));
            return 0;
        }

    private:
        SqliteHelper _sql_helper;
    };

    // 交换机数据内存管理类
    class ExchangeManager
    {
    public:
        using Ptr = std::shared_ptr<ExchangeManager>;
        ExchangeManager(const std::string &dbfile) : _mapper(dbfile)
        {
            // 将数据还原
            _exchanges = _mapper.Recovery();
        }
        // 声明交换机
        bool DeclareExchange(const std::string &name,
                             const ExchangeType &type,
                             const bool durable,
                             const bool auto_del,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_exchanges.count(name))
            {
                // 存在就直接返回
                //DLOG("当前交换机%s已经存在了", name.c_str());
                return true;
            }
            auto exc = std::make_shared<Exchange>(name, type, durable, auto_del, args);
            // 判断是否需要持久保存
            if (durable == true)
            {
                bool ret = _mapper.Insert(exc);
            }
            _exchanges.insert(std::make_pair(name, exc));
            return true;
        }
        // 删除交换机
        void DeleteExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end())
            {
                // 不存在就跳过
                return;
            }
            if (it->second->durable == true)
                _mapper.Remove(name); // 如果是持久化保存的就去数据库删除
            _exchanges.erase(name);
        }
        // 获取指定交换机
        Exchange::Ptr SelectExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto exc = _exchanges.find(name);
            if (exc == _exchanges.end())
            {
                DLOG("不存在该交换机:%s", name.c_str());
                return Exchange::Ptr();
            }
            return exc->second;
        }
        // 该交换机是否存在
        bool Exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto exc = _exchanges.find(name);
            if (exc == _exchanges.end())
            {
                return false;
            }
            return true;
        }
        // 销毁所有交换机
        void Clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.RemoveTable();
            _exchanges.clear();
        }
        size_t size() { return _exchanges.size(); }

    private:
        std::mutex _mutex;
        ExchangeMapper _mapper;                                    // 从这个数据库中可以拿到交换机的数据
        std::unordered_map<std::string, Exchange::Ptr> _exchanges; // 用来在内存中保存交换机的数据
    };
}